using System;
using System.Text.RegularExpressions;

namespace ExtremeSwank.Authentication.OpenID.Plugins.Discovery
{
    /// <summary>
    /// Yadis Discovery Plugin.
    /// Provides everything needed to perform Yadis discovery.
    /// Depends on XRDS plugin to decode resulting XRDS document.
    /// </summary>
    [Serializable]
    public class Yadis : IDiscovery
    {
        const string _Name = "Yadis Discovery Plugin";
        private StateContainer _Parent;

        /// <summary>
        /// Gets the human-readable name of the discovery plugin.
        /// </summary>
        /// <remarks>Always returns "Yadis Discovery Plugin".</remarks>
        public string Name
        {
            get
            {
                return _Name;
            }
        }
        /// <summary>
        /// Parent OpenID object.
        /// </summary>
        public StateContainer Parent
        {
            get { return _Parent; }
            set { _Parent = value; }
        }
        ProtocolVersion _PV;
        /// <summary>
        /// Not used.  Always returns null.
        /// </summary>
        /// <param name="openid">Claimed identifier.</param>
        /// <returns>Null</returns>
        public string[] ProcessID(string openid)
        {
            return null;
        }
        /// <summary>
        /// Perform Yadis discovery on a HTTP response, automatically retrieving and processing
        /// discovered documents.
        /// </summary>
        /// <param name="content">HTTP response content to parse.</param>
        /// <returns>String array containing two string arrays, first lists server endpoints, the second
        /// lists local identifiers (delegates).</returns>
        /// <remarks><para>In the two arrays, each of the discovered entry indexes are numerically matched.  
        /// An OpenID Server in the first array at index 1 will have its matching discovered delegate
        /// at index 1 in the second array.</para>
        /// <para>
        /// For instance, In cases where
        /// an OpenID Server endpoint is discovered without a Delegate ID, the matching index in the 
        /// second array will be set to null.
        /// </para>
        /// </remarks>
        public string[][] Discover(string content)
        {
            string xrds_url = GetURL(content);
            if (xrds_url != "")
            {
                XRDS x = new XRDS(Parent);
                string actualLocation = null;
                string xrdsdoc = Utility.MakeRequest(xrds_url, out actualLocation);
                if (xrdsdoc != null)
                {
                    string[][] ret = x.Discover(xrdsdoc);
                    _PV = x.Version;
                    return ret;
                }
                return null;
            }
            return null;
        }
        private string GetURL(string content)
        {
            string[] arrcon = content.Split('\n');
            int i = 0;
            while (i < arrcon.Length)
            {
                if (arrcon[i].StartsWith("X-XRDS-Location:"))
                {
                    char[] delimiter = { ':' };
                    string[] keyval = arrcon[i].Split(delimiter, 2);
                    string newurl = keyval[1].Trim();
                    return newurl;
                }
                i++;
            }

            string newcontent = Utility.RemoveHtmlComments(content);

            Regex xrds1 = new Regex("<meta[^>]*http-equiv=\"X-XRDS-Location\"[^>]*content=\"([^\"]+)\"[^>]*");
            Regex xrds2 = new Regex("<meta[^>]*content=\"([^\"]+)\"[^>]*http-equiv=\"X-XRDS-Location\"[^>]*");
            Match matches1 = xrds1.Match(newcontent);
            Match matches2 = xrds2.Match(newcontent);

            string url = "";

            if (matches1.Groups[1].Value != "") { url = matches1.Groups[1].Value; }
            else if (matches2.Groups[1].Value != "") { url = matches2.Groups[1].Value; }

            if (url != "")
            {
                return url;
            }
            return "";
        }
        /// <summary>
        /// Highest version of OpenID protocol supported by the discovered Identity Provider.
        /// </summary>
        public ProtocolVersion Version
        {
            get
            {
                return _PV;
            }
        }
        /// <summary>
        /// Creates a new Yadis object, automatically attaches to supplied
        /// StateContainer object.
        /// </summary>
        /// <param name="state">Parent StateContainer object.</param>
        public Yadis(StateContainer state)
        {
            Parent = state;
            state.RegisterPlugin(this);
        }

        /// <summary>
        /// Creates a new Yadis object, automatically attaches to supplied
        /// OpenIDConsumer object.
        /// </summary>
        /// <param name="openid"></param>
        public Yadis(OpenIDConsumer openid)
        {
            Parent = openid.StateContainer;
            Parent.RegisterPlugin(this);
        }

        /// <summary>
        /// Get the human-readable name of this plug-in.
        /// </summary>
        /// <returns>A string containing the plug-in name.</returns>
        public override string ToString()
        {
            return Name;
        }
    }
}
